﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.MetadirectoryServices;
using Microsoft.MetadirectoryServices.DetachedObjectModel;
using Lithnet.GoogleApps.ManagedObjects;
using Lithnet.MetadirectoryServices;

namespace Lithnet.GoogleApps.MA.UnitTests
{
    [TestClass]
    public class UnitTestUser
    {
        public UnitTestUser()
        {
            UnitTestCore.Initialize();
        }

        private CSEntryChange BuildBasicUser()
        {
            CSEntryChangeDetached csentry = new CSEntryChangeDetached(Guid.NewGuid(), ObjectModificationType.Unconfigured, MAImportError.Success, null);
            csentry.DN = string.Format("{0}@{1}", Guid.NewGuid().ToString(), Properties.Settings.Default.TestDomainSuffix);
            csentry.ObjectModificationType = ObjectModificationType.Add;
            csentry.ObjectType = "user";

            IList<object> aliases = new List<object>() 
                {
                    string.Format("{0}@{1}", Guid.NewGuid().ToString(), Properties.Settings.Default.TestDomainSuffix),
                    string.Format("{0}@{1}", Guid.NewGuid().ToString(), Properties.Settings.Default.TestDomainSuffix)
                };

            csentry.CreateAttributeAdd("name_givenName", "test1");
            csentry.CreateAttributeAdd("name_familyName", "test2");
            csentry.CreateAttributeAdd("suspended", false);
            csentry.CreateAttributeAdd("includeInGlobalAddressList", true);
            csentry.CreateAttributeAdd("orgUnitPath", "/");
            csentry.CreateAttributeAdd("notes_value", "my notes");
            csentry.CreateAttributeAdd("notes_contentType", "text_plain");
            csentry.CreateAttributeAdd("primaryEmail", csentry.DN);
            csentry.CreateAttributeAdd("aliases", aliases);

            return csentry;
        }

        private CSEntryChange UpdateBasicUser(string dn)
        {
            CSEntryChangeDetached csentry = new CSEntryChangeDetached(Guid.NewGuid(), ObjectModificationType.Unconfigured, MAImportError.Success, null);
            csentry.DN = dn;
            csentry.ObjectModificationType = ObjectModificationType.Update;
            csentry.ObjectType = "user";

            IList<object> aliases = new List<object>() 
                {
                    string.Format("{0}@{1}", Guid.NewGuid().ToString(), Properties.Settings.Default.TestDomainSuffix),
                    string.Format("{0}@{1}", Guid.NewGuid().ToString(), Properties.Settings.Default.TestDomainSuffix)
                };

            csentry.CreateAttributeReplace("name_givenName", "test3");
            csentry.CreateAttributeReplace("name_familyName", "test4");
            csentry.CreateAttributeReplace("suspended", true);
            csentry.CreateAttributeReplace("includeInGlobalAddressList", false);
            csentry.CreateAttributeReplace("orgUnitPath", "/");
            csentry.CreateAttributeReplace("notes_value", "my notes 2");
            csentry.CreateAttributeReplace("notes_contentType", "text_html");
            csentry.CreateAttributeReplace("primaryEmail", dn);
            csentry.CreateAttributeReplace("aliases", aliases);

            return csentry;
        }


        [TestMethod]
        public void UserAddBasic()
        {
            UnitTestCore.Config.AddressesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.ExternalIDsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.IMsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.OrganizationsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.PhonesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.RelationsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.WebsitesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.ReloadSchema();

            CSEntryChange csentry = this.BuildBasicUser();

            try
            {
                UnitTestCore.PutCSEntryAndThrowOnError(csentry);

                User user = UserRequestFactory.Get(csentry.DN);

                EvaluateBasicUser(user, csentry.DN, csentry.GetValueAdds<string>("aliases"));
            }
            finally
            {
                UnitTestCore.DeleteUser(csentry.DN);
            }
        }

        [TestMethod]
        public void UserUpdateBasic()
        {
            UnitTestCore.Config.AddressesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.ExternalIDsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.IMsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.OrganizationsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.PhonesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.RelationsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.WebsitesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.ReloadSchema();

            CSEntryChange csentry = this.BuildBasicUser();
            IList<string> aliases = csentry.GetValueAdds<string>("aliases");
            try
            {
                UnitTestCore.PutCSEntryAndThrowOnError(csentry);

                User user = UserRequestFactory.Get(csentry.DN);

                EvaluateBasicUser(user, csentry.DN, aliases);

                csentry = this.UpdateBasicUser(csentry.DN);

                UnitTestCore.PutCSEntryAndThrowOnError(csentry);
                System.Threading.Thread.Sleep(1000);
                user = UserRequestFactory.Get(csentry.DN);

                EvaluateBasicUser2(user, csentry.DN, aliases);

            }
            finally
            {
                UnitTestCore.DeleteUser(csentry.DN);
            }
        }

        [TestMethod]
        public void UserAddExternalIDsJson()
        {
            UnitTestCore.Config.AddressesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.ExternalIDsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.IMsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.OrganizationsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.PhonesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.RelationsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.WebsitesAttributeFormat = GoogleArrayMode.Json;

            CSEntryChange csentry = this.BuildBasicUser();

            try
            {

                List<ExternalID> ids = new List<ExternalID>()
                {
                    new ExternalID() { Type = "account", Value = "id1" }
                };

                string idsSerialized = UnitTestCore.Serialize(ids);

                csentry.CreateAttributeAdd("externalIds", idsSerialized);

                UnitTestCore.PutCSEntryAndThrowOnError(csentry);

                User user = UserRequestFactory.Get(csentry.DN);

                EvaluateBasicUser(user, csentry.DN, csentry.GetValueAdds<string>("aliases"));

                Assert.IsNotNull(user.ExternalIds);
                Assert.AreEqual(1, user.ExternalIds.Count);
                Assert.AreEqual("id1", user.ExternalIds[0].Value);
                Assert.AreEqual("account", user.ExternalIds[0].Type);
                Assert.IsNotNull(user.CreationTime);

            }
            finally
            {
                UnitTestCore.DeleteUser(csentry.DN);
            }
        }

        [TestMethod]
        public void UserAddExternalIDsFlattened()
        {
            UnitTestCore.Config.AddressesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.ExternalIDsAttributeFormat = GoogleArrayMode.FlattenKnownTypes;
            UnitTestCore.Config.IMsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.OrganizationsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.PhonesAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.RelationsAttributeFormat = GoogleArrayMode.Json;
            UnitTestCore.Config.WebsitesAttributeFormat = GoogleArrayMode.Json;

            CSEntryChange csentry = this.BuildBasicUser();

            try
            {
                csentry.CreateAttributeAdd("externalIds_customID1", "id1");
                csentry.CreateAttributeAdd("externalIds_customID2", "id2");

                UnitTestCore.PutCSEntryAndThrowOnError(csentry);

                User user = UserRequestFactory.Get(csentry.DN);

                EvaluateBasicUser(user, csentry.DN, csentry.GetValueAdds<string>("aliases"));

                Assert.IsNotNull(user.ExternalIds);
                Assert.AreEqual(2, user.ExternalIds.Count);
                Assert.AreEqual("id1", user.ExternalIds[0].Value);
                Assert.AreEqual("customID1", user.ExternalIds[0].Type);
                Assert.AreEqual("id2", user.ExternalIds[1].Value);
                Assert.AreEqual("customID2", user.ExternalIds[1].Type);
            }
            finally
            {
                UnitTestCore.DeleteUser(csentry.DN);
            }
        }

        private static void EvaluateBasicUser(User user, string dn, IList<string> expectedAliases)
        {
            Assert.AreEqual("test1", user.Name.GivenName);
            Assert.AreEqual("test2", user.Name.FamilyName);
            Assert.AreEqual(false, user.Suspended);
            Assert.AreEqual(true, user.IncludeInGlobalAddressList);
            Assert.AreEqual("/", user.OrgUnitPath);
            Assert.AreEqual("my notes", user.Notes.Value);
            Assert.AreEqual("text_plain", user.Notes.ContentType);
            CollectionAssert.AreEquivalent(expectedAliases.ToArray(), user.Aliases);
            Assert.AreEqual(dn, user.PrimaryEmail);
            Assert.IsNotNull(user.CreationTime);
        }

        private static void EvaluateBasicUser2(User user, string dn, IList<string> expectedAliases)
        {
            Assert.AreEqual("test3", user.Name.GivenName);
            Assert.AreEqual("test4", user.Name.FamilyName);
            Assert.AreEqual(true, user.Suspended);
            Assert.AreEqual(false, user.IncludeInGlobalAddressList);
            Assert.AreEqual("/", user.OrgUnitPath);
            Assert.AreEqual("my notes 2", user.Notes.Value);
            Assert.AreEqual("text_html", user.Notes.ContentType);
            CollectionAssert.AreEquivalent(expectedAliases.ToArray(), user.Aliases);
            Assert.AreEqual(dn, user.PrimaryEmail);
            Assert.IsNotNull(user.CreationTime);
        }
    }
}